#
#        Python GUI - File references and types - Generic
#
#        Classes for dealing with file references and file types
#        in as platform-independent a manner as possible.
#
#        In this view of things, a file reference consists
#        of two parts:
#
#             1) A directory reference, whose nature is
#                    platform-dependent,
#
#             2) A name.
#

import os
from Properties import Properties, overridable_property

class FileRef(Properties):
    """A FileRef is an object representing a file system
    object in a platform-independent way."""

    dir = overridable_property('dir', "DirRef representing the parent directory.")
    name = overridable_property('name', "Name of the file (last pathname component).")
    path = overridable_property('path', "Full pathname of the file.")

    _dir = None        # DirRef representing the parent directory
    _name = None    # Name, including type suffix if any

    #
    #        Properties
    #

    def get_dir(self):
        return self._dir

    def set_dir(self, x):
        if not isinstance(x, DirRef):
            x = DirRef(path = x)
        self._dir = x

    def get_name(self):
        "Return the name of the file."
        return self._name

    def set_name(self, x):
        "Set the name of the file."
        self._name = x
    
    def get_path(self):
        return os.path.join(self._dir.path, self._name)
    
    def set_path(self, x):
        d, n = os.path.split(x)
        self._dir = DirRef(path = d)
        self._name = n

    #
    #        Methods
    #

    def open(self, mode, file_type = None):
        """Open the file with the given mode and return a file object. On
        platforms which have file-type metadata (e.g. Macintosh), if the
        mode contains 'w' and a file_type is specified, the newly-created
        file will be given the specified type."""
        f = open(self.path, mode)
        if "w" in mode and file_type:
            self._set_type(file_type)
        return f
    
    def _set_type(self, file_type):
        #  Platforms which have file-type metadata (e.g. Macintosh) use this
        #  to set the type of a file.
        pass

    def __str__(self):
        return "FileRef(%r)" % self.path

#-------------------------------------------------------------------------

class DirRef(Properties):
    """A DirRef is an object representing a directory in the
    file system. Its representation is completely platform
    dependent."""

    _path = None

    path = overridable_property('path', "Full pathname of the directory.")

    def get_path(self):
        return self._path

    def set_path(self, x):
        self._path = x

    def __str__(self):
        return "GUI.DirRef(%r)" % self.path

#-------------------------------------------------------------------------

class FileType(Properties):
    """A FileType is a multi-platform representation of a file type."""
    
    _mac_creator = None
    _mac_type = None
    _suffix = None
    
    mac_creator = overridable_property('mac_creator', "Macintosh 4-character creator code")
    mac_type = overridable_property('mac_type', "Macintosh 4-character type code")
    suffix = overridable_property('suffix', "Filename suffix (without dot)")
    
    def get_mac_creator(self):
        return self._mac_creator
    
    def set_mac_creator(self, x):
        self._mac_creator = x

    def get_mac_type(self):
        return self._mac_type
    
    def set_mac_type(self, x):
        self._mac_type = x

    def get_suffix(self):
        return self._suffix
    
    def set_suffix(self, x):
        self._suffix = x
    
    def _matches(self, name, mac_type):
        #  Return true if the given name or type code matches that of
        #  this file type.
        this_mac_type = self._mac_type
        this_suffix = self._suffix
        if this_mac_type and mac_type == this_mac_type:
            return True
        #  Allow generic text files to match typeless files for MacOSX
        if not this_suffix and this_mac_type == "TEXT" and mac_type == "\0\0\0\0":
            return True
        if this_suffix and _matches_suffix(name, this_suffix):
            return True
        return False
    
    def _add_suffix(self, name):
        #  Force the given name to have the appropriate suffix for this file
        #  type. Platforms which have other means of representing file types
        #  (e.g. Macintosh) may override this.
        suffix = self._suffix
        if suffix and not _matches_suffix(name, suffix):
            name = "%s.%s" % (name, suffix)
        return name
    
#-------------------------------------------------------------------------

def _matches_suffix(name, suffix):
    #  Test case-insensitively whether the given filename has
    #  the given suffix.
    return name.lower().endswith("." + suffix.lower())
